package com.ratta.supernote.note.plugincore.modules;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.ratta.supernote.note.plugincore.NativeNoteAPISpec;
import com.ratta.supernote.note.plugincore.api.NoteDataCacheApi;
import com.ratta.supernote.note.plugincore.api.NoteLibAPI;
import com.ratta.supernote.note.plugincore.bean.ImageData;
import com.ratta.supernote.note.plugincore.core.PluginAppAPI;
import com.ratta.supernote.note.plugincore.notedata.PenInfo;
import com.ratta.supernote.note.plugincore.utils.BitmapUtils;
import com.ratta.supernote.note.plugincore.utils.FileUtils;
import com.ratta.supernote.note.plugincore.utils.UiHandler;

import java.io.File;
import java.text.Normalizer;
import java.util.Objects;


/**
 * Interface provided to RN for operating Note data
 */
public class RNNoteAPIModule extends NativeNoteAPISpec {
    private final String TAG = RNNoteAPIModule.class.getName();

    private final String IMAGE_RESULT_KEY_SUCCESS = "success";
    private final String IMAGE_RESULT_KEY_ERROR_CODE = "errorCode";
    private final String IMAGE_RESULT_KEY_ERROR_MSG = "errorMsg";

    private final int IMAGE_RESULT_KEY_ERROR_CODE_PATH_NULL = 101;
    private final int IMAGE_RESULT_KEY_ERROR_CODE_DATA_WRONG = 102;
    private final int IMAGE_RESULT_KEY_ERROR_CODE_TOO_BIG= 103;

    PluginAppAPI pluginApp;

    public RNNoteAPIModule(ReactApplicationContext reactContext, PluginAppAPI pluginApp) {
        super(reactContext);
        this.pluginApp = pluginApp;
    }

    @Override
    public void insertNoteImage(String imgPath, Promise promise) {
        Log.i(TAG,"insertNoteImage imagePath:"+imgPath);
        WritableMap result = Arguments.createMap();
        if (TextUtils.isEmpty(imgPath)) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_PATH_NULL);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image path is null");

            promise.resolve(result);
            return;
        }

        if(BitmapUtils.isBitmapOutOf2560(imgPath)) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_TOO_BIG);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image is too Big!(Out of 2560X2560)");
            promise.resolve(result);
            return;
        }

        Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
        if (bitmap == null) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_DATA_WRONG);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image data is error");
            promise.resolve(result);
            return;
        }

        ImageData oldImageData = NoteDataCacheApi.getInstance().getNoteImageData();
        if (oldImageData != null) {
            oldImageData.recycle();
        }
        ImageData imageData = new ImageData(bitmap, null);
        NoteDataCacheApi.getInstance().setNoteImageData(imageData);
        result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,true);
        promise.resolve(result);
        UiHandler.getInstance().handler().post(new Runnable() {
            @Override
            public void run() {
                NoteDataCacheApi.getInstance().onNoteImageChange();
            }
        });


    }

    @Override
    public void modifyNoteImage(ReadableMap imageData, Promise promise) {
        String imagePath = imageData.getString("path");
        WritableMap result = Arguments.createMap();
        Log.i(TAG,"modifyNoteImage imageData path:"+imagePath);
        if (TextUtils.isEmpty(imagePath)) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_PATH_NULL);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image path is null");

            promise.resolve(result);
            return;
        }
        Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
        if (bitmap == null) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_DATA_WRONG);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image data is error");
            promise.resolve(result);
            return;
        }
        if(BitmapUtils.isBitmapOutOf2560(imagePath)) {
            result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,false);
            result.putInt(IMAGE_RESULT_KEY_ERROR_CODE, IMAGE_RESULT_KEY_ERROR_CODE_TOO_BIG);
            result.putString(IMAGE_RESULT_KEY_ERROR_MSG,"Image is too Big!(Out of 2560X2560)");
            promise.resolve(result);
            bitmap.recycle();
            return;
        }
        ImageData noteImageData = NoteDataCacheApi.getInstance().getNoteImageData();
        Rect rect;
        if (imageData.hasKey("rect")) {
            ReadableMap rectMap = imageData.getMap("rect");
            int left = rectMap.getInt("left");
            int top = rectMap.getInt("top");
            int right = rectMap.getInt("right");
            int bottom = rectMap.getInt("bottom");
            rect = new Rect(left, top, right, bottom);
            Log.i(TAG,"modifyNoteImage change rect:"+rect);
        } else {
            rect = Objects.requireNonNull(noteImageData).rect;
        }
        Log.i(TAG,"modifyNoteImage rect:"+rect);
        Objects.requireNonNull(noteImageData).recycle();

        ImageData image = new ImageData(bitmap, rect);
        image.isPluginEdit = true;
        Log.i(TAG,"modifyNoteImage bitmap:"+bitmap);
        NoteDataCacheApi.getInstance().setNoteImageData(image);
        result.putBoolean(IMAGE_RESULT_KEY_SUCCESS,true);
        promise.resolve(result);
        UiHandler.getInstance().handler().post(new Runnable() {
            @Override
            public void run() {
                NoteDataCacheApi.getInstance().onNoteImageChange();
            }
        });


    }

    @Override
    public void getCurrentNoteImageInfo(Promise promise) {
        ImageData noteImageData = NoteDataCacheApi.getInstance().getNoteImageData();
        if(noteImageData == null) {
            promise.resolve(null);
            return;
        }

        Bitmap bitmap = Objects.requireNonNull(NoteDataCacheApi.getInstance().getNoteImageData()).bitmap;

        if (bitmap == null) {
            promise.resolve(null);
            return;
        }

        // 保存临时文件
        String tempImagePath = getCurrentActivity().getCacheDir() + File.separator + "tempImage.png";
        File imageFile = new File(tempImagePath);
        if (imageFile.exists()) {
            imageFile.delete();
        }
        Log.i(NAME,"getCurrentNoteImagePath tempImagePath:"+tempImagePath);
        boolean saveRe = FileUtils.saveBitmapToPng(bitmap, tempImagePath);

        if(!saveRe) {
            promise.resolve(null);
            return;
        }
        WritableMap params = Arguments.createMap();
        params.putString("path", tempImagePath);
        params.putInt("width", bitmap.getWidth());
        params.putInt("height", bitmap.getHeight());
        WritableMap rectMap = Arguments.createMap();
        Rect rect = noteImageData.rect;
        rectMap.putInt("left", rect.left);
        rectMap.putInt("top", rect.top);
        rectMap.putInt("right", rect.right);
        rectMap.putInt("bottom", rect.bottom);
        params.putMap("rect", rectMap);
        promise.resolve(params);
    }

    @Override
    public void getCurrentNoteImageLassoRect(Promise promise) {
        ImageData noteImageData = NoteDataCacheApi.getInstance().getNoteImageData();
        if(noteImageData == null) {
            promise.resolve(null);
            return;
        }

        Bitmap bitmap = Objects.requireNonNull(NoteDataCacheApi.getInstance().getNoteImageData()).bitmap;

        if (bitmap == null) {
            promise.resolve(null);
            return;
        }
        WritableMap rectMap = Arguments.createMap();
        Rect rect = noteImageData.rect;
        rectMap.putInt("left", rect.left);
        rectMap.putInt("top", rect.top);
        rectMap.putInt("right", rect.right);
        rectMap.putInt("bottom", rect.bottom);
        promise.resolve(rectMap);

    }

    @Override
    public void getPenInfo(Promise promise) {
        PenInfo penInfo = pluginApp.getPenInfo();
        WritableMap params = Arguments.createMap();
        params.putInt("type", penInfo.type);
        params.putInt("width", penInfo.width);
        params.putInt("color", penInfo.color);
        params.putBoolean("isSplit", penInfo.isSplit);
        promise.resolve(params);

    }

    @Override
    public void setPenInfo(ReadableMap readableMap, Promise promise) {
        PenInfo penInfo = pluginApp.getPenInfo();
        penInfo.type = readableMap.getInt("type");
        penInfo.color = readableMap.getInt("color");
        penInfo.width = readableMap.getInt("width");
        penInfo.isSplit = readableMap.getBoolean("isSplit");
        Log.i(TAG, "NoteAPI setPenInfo:" + penInfo);

        NoteLibAPI.getInstance().setPenInfo(penInfo);
        promise.resolve(true);
    }

    @Override
    public void getLayers(Promise promise) {
        promise.resolve(pluginApp.getLayersJson());
    }

    @Override
    public void setLayers(String layers, Promise promise) {
        pluginApp.setLayersJson(layers);
        promise.resolve(true);

    }

    @Override
    public void getData(String key, Promise promise) {

    }

    @Override
    public void saveData(String key, String value, Promise promise) {


    }

    @Override
    public void getAllData(Promise promise) {

    }

    // 对字符串进行重音符和大小写不敏感的归一化处理
    public void normalize(String text, Promise promise) {
        promise.resolve(Normalizer.normalize(text, Normalizer.Form.NFD)
                .replaceAll("\\p{M}", ""));

    }


    /**
     * 开启快刷模式
     *
     * @param enable
     */
    @Override
    public void setFullAuto(boolean enable) {
        NoteLibAPI.getInstance().setFullAuto(enable, "RN Plugin");

    }
}
